package com.bsj.media.media.resample.quality;

public class FuncDef {

	private static final double M_PI = 3.14159265358979323846; /* pi */
	
	public double[] table;
	public int oversample;

	public static final double[] kaiser12_table = { 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,
			0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, 0.84290116, 0.81573067, 0.78710866,
			0.75723148, 0.72629970, 0.69451601, 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014,
			0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490, 0.28829195, 0.26276832, 0.23854851,
			0.21567274, 0.19416736, 0.17404546, 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178,
			0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, 0.02584161, 0.02127838, 0.01736250,
			0.01402878, 0.01121463, 0.00886058, 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438,
			0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734, 0.00001000, 0.00000000 };
	/*
	 * public static final double[] kaiser12_table = { 0.99440475, 1.00000000, 0.99440475,
	 * 0.97779076, 0.95066529, 0.91384741, 0.86843014, 0.81573067, 0.75723148,
	 * 0.69451601, 0.62920216, 0.56287762, 0.49704014, 0.43304576, 0.37206735,
	 * 0.31506490, 0.26276832, 0.21567274, 0.17404546, 0.13794294, 0.10723616,
	 * 0.08164178, 0.06075685, 0.04409466, 0.03111947, 0.02127838, 0.01402878,
	 * 0.00886058, 0.00531256, 0.00298291, 0.00153438, 0.00069463, 0.00025272,
	 * 0.0000527734, 0.00000500, 0.00000000};
	 */
	public static final double[] kaiser10_table = { 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,
			0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, 0.56155915, 0.50119680, 0.44221549,
			0.38553619, 0.33194107, 0.28205962, 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451,
			0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739, 0.00488951, 0.00257636, 0.00115101,
			0.00035515, 0.00000000, 0.00000000 };

	public static final double[] kaiser8_table = { 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,
			0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, 0.63451750, 0.58014482, 0.52566725,
			0.47185369, 0.41941150, 0.36897272, 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
			0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, 0.01563093, 0.00959968, 0.00527363,
			0.00233883, 0.00050000, 0.00000000 };

	public static final double[] kaiser6_table = { 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
			0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, 0.71712752, 0.67172623, 0.62508937,
			0.57774224, 0.53019925, 0.48295561, 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058,
			0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600, 0.05031820, 0.03607231, 0.02432151,
			0.01487334, 0.00752000, 0.00000000 };

	public static FuncDef setKAISER12() {
		FuncDef def = new FuncDef();
		def.table = kaiser12_table;
		def.oversample = 64;
		return def;
	}

	public static FuncDef setKAISER10() {
		FuncDef def = new FuncDef();
		def.table = kaiser10_table;
		def.oversample = 32;
		return def;
	}

	public static FuncDef setKAISER8() {
		FuncDef def = new FuncDef();
		def.table = kaiser8_table;
		def.oversample = 32;
		return def;
	}

	public static FuncDef setKAISER6() {
		FuncDef def = new FuncDef();
		def.table = kaiser6_table;
		def.oversample = 32;
		return def;
	}

	public static float sinc(float cutoff, float x, int N, final FuncDef window_func) {
		/* fprintf (stderr, "%f ", x); */
		float xx = x * cutoff;
		if (Math.abs(x) < 1e-6)
			return cutoff;
		else if (Math.abs(x) > .5 * N)
			return 0;
		/* FIXME: Can it really be any slower than this? */
		return (float) (cutoff * Math.sin(M_PI * xx) / (M_PI * xx)
				* compute_func((float) Math.abs(2. * x / N), window_func));
	}

	public static double compute_func(float x, final FuncDef func) {
		float y, frac;
		double[] interp = new double[4];
		int ind;
		y = x * func.oversample;
		ind = (int) Math.floor(y);
		frac = (y - ind);
		/* CSE with handle the repeated powers */
		interp[3] = -0.1666666667 * frac + 0.1666666667 * (frac * frac * frac);
		interp[2] = frac + 0.5 * (frac * frac) - 0.5 * (frac * frac * frac);
		/* interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac; */
		interp[0] = -0.3333333333 * frac + 0.5 * (frac * frac) - 0.1666666667 * (frac * frac * frac);
		/* Just to make sure we don't have rounding problems */
		interp[1] = 1.f - interp[3] - interp[2] - interp[0];

		/* sum = frac*accum[1] + (1-frac)*accum[2]; */
		return interp[0] * func.table[ind] + interp[1] * func.table[ind + 1] + interp[2] * func.table[ind + 2]
				+ interp[3] * func.table[ind + 3];
	}
}
